package com.hsogoo.avatar.executor;

import java.util.concurrent.Callable;

import org.apache.commons.lang.StringUtils;

import com.hsogoo.avatar.control.FallBack;
import com.hsogoo.avatar.control.LimitControl;
import com.hsogoo.avatar.enums.AvatarResult;
import com.hsogoo.avatar.model.AvatarRequest;
import com.hsogoo.avatar.model.AvatarResponse;
import com.hsogoo.avatar.model.ProviderMethod;
import com.hsogoo.avatar.registry.LimitControlRegistry;
import com.hsogoo.avatar.registry.ProviderMethodRegistry;
import com.hsogoo.avatar.transport.AvatarChannel;
import com.hsogoo.avatar.utils.ExceptionUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * Created by za-huangsaigang on 2018/10/24.
 */
@Slf4j
public class AvatarTask implements Runnable{

    private AvatarChannel channel;
    private AvatarRequest request;

    public AvatarTask(AvatarChannel channel, AvatarRequest request) {
        this.channel = channel;
        this.request = request;
    }

    @Override
    public void run() {
        AvatarResponse response = new AvatarResponse();
        StringBuilder sb = new StringBuilder();
        String providerName = request.getInterfaceName();
        sb.append(providerName).append(".").append(request.getMethodName());
        //支持方法重载
        Class[] paramTypes = request.getArgTypes();
        if(paramTypes != null && paramTypes.length > 0){
            for(Class param : paramTypes){
                sb.append("#").append(param.getSimpleName());
            }
        }
        String providerKey = sb.toString();
        //获取服务提供者的方法
        ProviderMethod providerMethod = ProviderMethodRegistry.getProviderMethod(providerKey);
        response.setProtocol(request.protocol());
        response.setRequestId(request.getRequestId());
        long timeout = request.getTimeout();
        Object result = null;
        LimitControl providerLimitControl = LimitControlRegistry.getLimitControl(providerName);
        LimitControl providerMethodLimitControl = LimitControlRegistry.getLimitControl(providerKey);
        //先拿provider级令牌
        long start = System.currentTimeMillis();
        if (providerLimitControl != null && !providerLimitControl.tryAcquire(timeout)) {
            //设置服务调用结果
            response.setFailResult(AvatarResult.OUT_OF_PROVIDER_LIMIT, AvatarResult.OUT_OF_PROVIDER_LIMIT.getMessage());
            log.error(String.format("{%s}provider limit can not get provider token...", providerName));
            channel.sendResponse(response);
            return;
        }
        long providerAcquireCost = System.currentTimeMillis() - start;
        //再拿provider方法级令牌
        if (providerMethodLimitControl != null && ! providerMethodLimitControl.tryAcquire(timeout - providerAcquireCost)) {
            log.error(String.format("{%s}provider method limit can not get provider token...", providerKey));
            if(StringUtils.isBlank(providerMethod.getProviderMethodConfig().getFallback())){
                response = FallBack.Default.invoke();
            }else{
                try{
                    Class clazz = Class.forName(providerMethod.getProviderMethodConfig().getFallback());
                    FallBack fallBack = (FallBack) clazz.newInstance();
                    response = fallBack.invoke();
                }catch (Exception e){
                    log.error(providerMethod.getProviderMethodConfig().getFallback() + "not found...");
                    response = FallBack.Default.invoke();
                }
            }
            channel.sendResponse(response);
            return;
        }
        try{
            result = providerMethod.getMethod().invoke(providerMethod.getBean(), request.getArgs());
            //设置服务调用结果
            response.setSuccessResult(result);
        }catch (Exception e){
            //设置服务调用结果
            response.setFailResult(AvatarResult.INVOKE_EXCEPTION, ExceptionUtil.getDetailMessage(e));
        }
        channel.sendResponse(response);
    }
}
